/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*          http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#include <string.h>

// this should be enough
static char buf[65536] = {};
static char code_buf[65536 + 128] = {}; // a little larger than `buf`
static char *code_format =
"#include <stdio.h>\n"
"int main() { "
"  unsigned result = %s; "
"  printf(\"%%u\", result); "
"  return 0; "
"}";
int choose(int range) {
    // 生成范围内的随机数的逻辑
    return rand() % range;
}

unsigned int gen_num() {
    // 生成随机数字的逻辑
    unsigned int  num = rand()%1000;
    assert(num<1010);
    // 将数字转换为字符串
    char num_str[12];
    sprintf(num_str, "%u", num);
    
    // 将数字字符串添加到生成的表达式中
    strcat(buf, num_str);
    return num;
}

void gen(char ch) {
    // 将指定的字符添加到生成的表达式中
    int len = strlen(buf);
    buf[len] = ch;
    buf[len + 1] = '\0';
}
char gen_rand_op() {
    // 生成随机操作符的逻辑
    char ops[] = {'+', '-', '*', '/'};
    int num_ops = sizeof(ops) / sizeof(ops[0]);
    
    // 随机选择一个操作符
    int index = rand() % num_ops;
    // 将操作符添加到生成的表达式中
    gen(ops[index]);
    return ops[index];
}

unsigned int gen_expr(){
  unsigned int res = 1;
  switch(choose(3)){
    case 0: res =  gen_num(); break;
    case 1: gen('('); res = gen_expr(); gen(')');  break;
    default: {
      unsigned int value1,value2;
      char op;
      int len = strlen(buf);
      op = buf[len-1];
      while((op!='+'&&op!='-'&&op!='*'&&op!='/')&& len>1){
        len--;
        op = buf[len-1];
      }
      value1 = gen_expr(); 
      if(op=='/' && value1 == 0){
        buf[0] = '0';
        buf[1] = '\0';
        return UINT16_MAX;
      }
      if(value1 == UINT16_MAX){
        buf[0] = '0';
        buf[1] = '\0';
        return UINT16_MAX;
      }
      op =  gen_rand_op(); 
      value2 = gen_expr();
      if(value2 == UINT16_MAX){
        buf[0] = '0';
        buf[1] = '\0';
        return UINT16_MAX;
      }
      switch (op){
      case '+' : return value1 + value2;
      case '-' : return value1 - value2;
      case '*' : return value1 * value2;
      case '/' :  {
        if(value2 != 0){
          return value1 / value2;
        }
        // division by zero
        buf[0] = '0';
        buf[1] = '\0';
        return UINT16_MAX;
      }
      default: assert(0);
    }
      break;
      }
  }
  if(res == UINT16_MAX){
    buf[0] = '0';
    buf[1] = '\0';
  }
  return res;
}
static void gen_rand_expr() {
  buf[0] = '\0';
  gen_expr();
  
}

int main(int argc, char *argv[]) {
  int seed = time(0);
  srand(seed);
  int loop = 1;
  if (argc > 1) {
    sscanf(argv[1], "%d", &loop);
  }
  int i;
  for (i = 0; i < loop; i ++) {
    gen_rand_expr();

    sprintf(code_buf, code_format, buf);

    FILE *fp = fopen("/tmp/.code.c", "w");
    assert(fp != NULL);
    fputs(code_buf, fp);
    fclose(fp);

    int ret = system("gcc /tmp/.code.c -o /tmp/.expr");
    if (ret != 0) continue;

    fp = popen("/tmp/.expr", "r");
    assert(fp != NULL);

    unsigned  result;
    int  rt = fscanf(fp, "%d", &result);
    assert(rt==1);
    pclose(fp);

    printf("%u %s\n", result, buf);

  }
  return 0;
}
